package io.renren.modules.gis_admin.service.impl;

import io.renren.common.exception.RenException;
import io.renren.common.utils.ApexUtils;
import io.renren.modules.gis_admin.dao.BasinConfigDao;
import io.renren.modules.gis_admin.dao.BasinRecordDao;
import io.renren.modules.gis_admin.dao.BasinSourceDao;
import io.renren.modules.gis_admin.dto.BasinConfigDTO;
import io.renren.modules.gis_admin.dto.ExecuteConfigDTO;
import io.renren.modules.gis_admin.dto.ExecuteResultDTO;
import io.renren.modules.gis_admin.dto.GisDataDTO;
import io.renren.modules.gis_admin.entity.BasinConfigEntity;
import io.renren.modules.gis_admin.entity.BasinRecordEntity;
import io.renren.modules.gis_admin.entity.BasinSourceEntity;
import io.renren.modules.gis_admin.enums.RecordTypeEnum;
import io.renren.modules.gis_admin.service.BasinConfigService;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
 * 子流域配置
 *
 * @author Mark iu1340@163.com
 * @since 1.0.0 2023-09-23
 */
@Slf4j
@Service
public class BasinConfigServiceImpl implements BasinConfigService {

  @Resource
  BasinConfigDao basinConfigDao;

  @Resource
  BasinRecordDao basinRecordDao;

  @Resource
  BasinSourceDao basinSourceDao;

  @Value("${basin.file.result-parent-path}")
  private String resultParentPath;

  private final Lock lock = new ReentrantLock();

  /**
   * 执行流程：保存记录 -> 保存子流域配置 -> 生成配置文件 -> 执行exe -> 整理结果 -> 更新记录 —> 返回结果
   * @param executeConfigDTO 配置
   * @return 图数据
   */
  @Override
  public ExecuteResultDTO execute(ExecuteConfigDTO executeConfigDTO) {
    boolean isExecuteLock = lock.tryLock();
    if (isExecuteLock) {
      try {
        Long sourceId = executeConfigDTO.getSourceId();
        List<BasinConfigDTO> configList = executeConfigDTO.getConfigList();
        BasinSourceEntity sourceEntity = basinSourceDao.selectById(sourceId);
        if (sourceEntity == null) {
          throw new RenException("sourceId错误");
        }
        String sourcePath = sourceEntity.getFilePath();
        String sourceName = sourceEntity.getSourceName();
        Long recordId = saveRecord(sourceId);
        saveConfig(recordId, configList);
        List<GisDataDTO> gisData = ApexUtils.process(sourcePath, configList);
        String resultPath = ApexUtils.moveResult(sourcePath, sourceName, resultParentPath);
        updateRecord(recordId, resultPath);
        ExecuteResultDTO result = new ExecuteResultDTO();
        result.setSourceId(sourceId);
        result.setSourceName(sourceName);
        result.setRecordId(recordId);
        result.setRecordName(basinRecordDao.selectById(recordId).getRecordName());
        result.setResultPath(resultPath);
        result.setGisData(gisData);
        return result;
      } catch (IOException | InterruptedException e) {
        throw new RuntimeException("apex run failed. executeConfigDTO: " + executeConfigDTO.toString(), e);
      } finally {
        lock.unlock();
      }
    } else {
      throw new RenException("当前正在执行，请稍后重试。");
    }
  }

  public Long saveRecord(Long sourceId) {
    BasinRecordEntity basinRecordEntity = new BasinRecordEntity();
    basinRecordEntity.setSourceId(sourceId);
    basinRecordEntity.setRecordName("record-" + System.currentTimeMillis());
    basinRecordEntity.setRecordType(RecordTypeEnum.NORMAL.getType());
    basinRecordDao.insert(basinRecordEntity);
    return basinRecordEntity.getId();
  }

  public void saveConfig(Long recordId, List<BasinConfigDTO> configList) {
    configList.forEach(config -> {
      BasinConfigEntity configEntity = new BasinConfigEntity();
      configEntity.setRecordId(recordId);
      configEntity.setBasinId(config.getBasinId());
      configEntity.setLandType(config.getLandType());
      configEntity.setNValue(config.getNValue());
      configEntity.setPValue(config.getPValue());
      basinConfigDao.insert(configEntity);
    });
  }

  public void updateRecord(Long recordId, String resultPath) {
    BasinRecordEntity recordEntity = basinRecordDao.selectById(recordId);
    recordEntity.setResultPath(resultPath);
    basinRecordDao.updateById(recordEntity);
  }
}